package com.ccrfid.rmc6.service.mattress;

import com.ccrfid.rmc6.appconfig.exception.pojo.AppException;
import com.ccrfid.rmc6.appconfig.exception.pojo.CustomErrors;
import com.ccrfid.rmc6.entity.mattress.BedEntity;
import com.ccrfid.rmc6.entity.mattress.BedHistoryEntity;
import com.ccrfid.rmc6.entity.mattress.MattressStateEntity;
import com.ccrfid.rmc6.pojo.dto.mattress.BedLayoutDto;
import com.ccrfid.rmc6.repository.mattress.BedHistoryRepository;
import com.ccrfid.rmc6.repository.mattress.BedRepository;
import com.ccrfid.rmc6.repository.mattress.MattressStateRepository;
import com.ccrfid.rmc6.repository.search.SearchCriteria;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.transaction.Transactional;
import javax.ws.rs.core.Response;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Service
@Transactional
public class BedServiceImpl implements BedService {
    private static final Logger logger = LoggerFactory.getLogger(BedServiceImpl.class);

    @Autowired
    private MattressService mattressService;
    @Autowired
    private BedRepository bedRepository;
    @Autowired
    private BedHistoryRepository bedHistoryRepository;
    @Autowired
    private MattressStateRepository mattressStateRepository;

    @Value("${ht.mattress.bed.rows}")
    private Integer rows;
    @Value("${ht.mattress.bed.cols}")
    private Integer cols;

    @Override
    public BedLayoutDto getBedLayout() {
        BedLayoutDto layoutDto = new BedLayoutDto();
        layoutDto.setRows(rows);
        layoutDto.setCols(cols);
        return layoutDto;
    }

    @Override
    public List<BedEntity> getAllBeds() {
        return bedRepository.getAllBy();
    }

    @Override
    public BedEntity createBed(BedEntity bedEntity) throws AppException {
        if (bedEntity == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.param_is_null.getCode(), CustomErrors.param_is_null.getReason(), "");
        }
        if (StringUtils.isEmpty(bedEntity.getBedSn())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.bed_sn_is_null.getCode(), CustomErrors.bed_sn_is_null.getReason(), "");
        }
        if (bedEntity.getRowNum() == null || bedEntity.getColNum() == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.bed_row_col_err.getCode(), CustomErrors.bed_row_col_err.getReason(), "");
        }
        if (bedRepository.existsByBedSn(bedEntity.getBedSn())) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.bed_sn_conflict.getCode(), CustomErrors.bed_sn_conflict.getReason(), "");
        }
        if (bedEntity.getMattressSn() != null) {
            if (bedRepository.existsByMattressSn(bedEntity.getMattressSn())) {
                throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                        CustomErrors.mattress_sn_conflict.getCode(), CustomErrors.mattress_sn_conflict.getReason(), "");
            }
        }
        return bedRepository.save(bedEntity);
    }

    @Override
    public BedEntity updateBedMattress(String bedSn, String mattressSn) throws AppException {
        if (!bedRepository.existsByBedSn(bedSn)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.bed_sn_not_found.getCode(), CustomErrors.bed_sn_not_found.getReason(), "");
        }
        if (bedRepository.existsByBedSnNotAndMattressSn(bedSn, mattressSn)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.mattress_sn_conflict.getCode(), CustomErrors.mattress_sn_conflict.getReason(), "");
        }
        BedEntity bedEntity = bedRepository.getByBedSn(bedSn);
        bedEntity.setMattressSn(mattressSn);
        return bedRepository.save(bedEntity);
    }

    @Override
    public Boolean deleteBed(String bedSn) throws AppException {
        if (!bedRepository.existsByBedSn(bedSn)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.bed_sn_not_found.getCode(), CustomErrors.bed_sn_not_found.getReason(), "");
        }
        bedRepository.deleteByBedSn(bedSn);

        //如果有入住记录，则退床
        BedHistoryEntity bedHistoryEntity = bedHistoryRepository.getByBedSnAndStopTimeIsNull(bedSn);
        if (bedHistoryEntity != null) {
            bedHistoryEntity.setStopTime(new Timestamp(Instant.now().toEpochMilli()));
            bedHistoryRepository.save(bedHistoryEntity);
        }
        return true;
    }

    @Override
    public Set<String> getAvailableMattresses() {
        Set<String> mattressSet = mattressService.getAvailableMattresses();
        if (mattressSet != null && mattressSet.size() > 0) {
            List<BedEntity> bedList = bedRepository.getAllByMattressSnIsNotNull();
            if (bedList != null && bedList.size() > 0) {
                for (BedEntity bedEntity : bedList) {
                    mattressSet.remove(bedEntity.getMattressSn());
                }
            }
        }
        return mattressSet;
    }

    @Override
    public BedEntity bedCheckIn(String bedSn, BedEntity entity) throws AppException {
        if (!bedRepository.existsByBedSn(bedSn)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.bed_sn_not_found.getCode(), CustomErrors.bed_sn_not_found.getReason(), "");
        }
        BedEntity bedEntity = bedRepository.getByBedSn(bedSn);
        bedEntity.setPersonnelId(entity.getPersonnelId());
        bedEntity.setPersonnelName(entity.getPersonnelName());
        bedRepository.save(bedEntity);
        //插入入住记录
        BedHistoryEntity bedHistoryEntity = bedHistoryRepository.getByBedSnAndStopTimeIsNull(bedSn);
        if (bedHistoryEntity == null) {
            bedHistoryEntity = new BedHistoryEntity();
        }
        bedHistoryEntity.setBedSn(bedSn);
        bedHistoryEntity.setMattressSn(bedEntity.getMattressSn());
        bedHistoryEntity.setPersonnelId(bedEntity.getPersonnelId());
        bedHistoryEntity.setPersonnelName(bedEntity.getPersonnelName());
        bedHistoryEntity.setStartTime(new Timestamp(Instant.now().toEpochMilli()));
        bedHistoryRepository.save(bedHistoryEntity);

        return bedEntity;
    }

    @Override
    public Boolean bedCheckOut(String bedSn) throws AppException {
        if (!bedRepository.existsByBedSn(bedSn)) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.bed_sn_not_found.getCode(), CustomErrors.bed_sn_not_found.getReason(), "");
        }
        //退床
        BedEntity bedEntity = bedRepository.getByBedSn(bedSn);
        bedEntity.setPersonnelId(null);
        bedEntity.setPersonnelName(null);
        bedRepository.save(bedEntity);
        //更新入住记录
        BedHistoryEntity bedHistoryEntity = bedHistoryRepository.getByBedSnAndStopTimeIsNull(bedSn);
        if (bedHistoryEntity != null) {
            bedHistoryEntity.setStopTime(new Timestamp(Instant.now().toEpochMilli()));
            bedHistoryRepository.save(bedHistoryEntity);
        }
        return true;
    }

    @Override
    public BedHistoryEntity getBedCheckInTime(String bedSn) {
        BedHistoryEntity bedHistoryEntity = bedHistoryRepository.getByBedSnAndStopTimeIsNull(bedSn);
        return bedHistoryEntity;
    }

    @Override
    public List<MattressStateEntity> getMattressStateHistory(String mattressSn, Timestamp startTime, Timestamp stopTime) {
        if (mattressSn != null && startTime != null && stopTime != null) {
            return mattressStateRepository.getAllByMattressSnAndRecordTimeBetween(mattressSn, startTime, stopTime);
        }
        return new ArrayList<>();
    }

    @Override
    public Page<MattressStateEntity> getMattressStateHistoryPage(SearchCriteria criteria, Pageable pageable) {
        return mattressStateRepository.search(criteria, pageable);
    }
}
